<?php

namespace App\Repositories;

use App\Contracts\Searchable;
use App\Entities\Vulnerability;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder;
use Illuminate\Support\Collection;
use LaravelDoctrine\ORM\Pagination\PaginatesFromRequest;

class VulnerabilityRepository extends AbstractSearchableRepository implements Searchable
{
    use PaginatesFromRequest;

    /**
     * Get paginated Vulnerabilities found in the File with the given ID
     *
     * @param int $fileId
     *
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findByFileQuery(int $fileId = 0)
    {
        if (!isset($fileId)) {
            $fileId = 0;
        }

        return $this->paginate(
            $this->createQueryBuilder($this->getQueryBuilderAlias())
                ->addSelect('COUNT(a.id) AS total_assets')
                ->leftJoin('v.assets', 'a')
                ->addCriteria(
                    Criteria::create()->where(
                        Criteria::expr()->eq(Vulnerability::FILE_ID, $fileId)
                    )
                )
                ->groupBy('v.id')
                ->orderBy('total_assets', Criteria::DESC)
                ->orderBy('v.severity', Criteria::DESC)
                ->getQuery(),
            $this->getPerPage(),
            $this->getPageName(),
            false
        )->setPageName($this->getPageName());
    }

    /**
     * Get paginated Vulnerabilities found in the Folder with the given ID
     *
     * @param int $folderId
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findByFolderQuery(int $folderId = 0)
    {
        if (!isset($folderId)) {
            $folderId = 0;
        }

        return $this->paginate(
            $this->createQueryBuilder($this->getQueryBuilderAlias())
                ->addSelect('COUNT(a.id) AS total_assets')
                ->leftJoin('v.assets', 'a')
                ->innerJoin('v.folders', 'f')
                ->addCriteria(
                    Criteria::create()->where(
                        Criteria::expr()->eq('f.id', $folderId)
                    )
                )
                ->groupBy('v.id')
                ->orderBy('total_assets', Criteria::DESC)
                ->orderBy('v.severity', Criteria::DESC)
                ->getQuery(),
            $this->getPerPage(),
            $this->getPageName(),
            false
        )->setPageName($this->getPageName());
    }

     /**
     * Get all the sorted, paginated Vulnerabilities related to a Asset
     *
     * @param int $assetId
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findByAssetQuery(int $assetId = 0)
    {
        if (!isset($assetId)) {
            $assetId = 0;
        }

        return $this->paginate(
            $this->createQueryBuilder($this->getQueryBuilderAlias())
                 ->addSelect("COUNT(a.id) AS total_assets")
                 ->leftJoin('v.assets', 'a')
                 ->leftJoin('v.assets', 'a2')
                 ->addCriteria(
                     Criteria::create()->where(
                         Criteria::expr()->eq('a2.id', $assetId)
                     )
                 )
                 ->groupBy('v.id')
                 ->orderBy('total_assets', Criteria::DESC)
                 ->orderBy('v.severity', Criteria::DESC)
                 ->getQuery(),
            $this->getPerPage(),
            $this->getPageName(),
            false
        )->setPageName($this->getPageName());
    }
    /**
     * Get paginated Vulnerabilities found in all the files.
     *
     * @param int $fileId
     *
     * @return \Illuminate\Pagination\LengthAwarePaginator
     */
    public function findAllQuery()
    {


        return $this->paginate(
            $this->createQueryBuilder($this->getQueryBuilderAlias())
                ->addSelect('COUNT(a.id) AS total_assets')
                ->leftJoin('v.assets', 'a')
                ->groupBy('v.id')
                ->orderBy('total_assets', Criteria::DESC)
                ->orderBy('v.severity', Criteria::DESC)
                ->getQuery(),
            $this->getPerPage(),
            $this->getPageName(),
            false
        )->setPageName($this->getPageName());
    }
    /**
     * @inheritdoc
     *
     * @return Collection
     */
    public function getSearchableFields(): Collection
    {
        return collect([Vulnerability::NAME]);
    }

    /**
     * @inheritdoc
     *
     * @return string
     */
    protected function getQueryBuilderAlias(): string
    {
        return 'v';
    }

    /**
     * @inheritdoc
     *
     * @return string
     */
    protected function getPageName(): string
    {
        return 'vulnerabilities_page';
    }

    /**
     * @inheritdoc
     *
     * @param QueryBuilder $queryBuilder
     * @return QueryBuilder
     */
    protected function addOrdering(QueryBuilder $queryBuilder): QueryBuilder
    {
        return $queryBuilder->orderBy('v.severity', Criteria::DESC);
    }
}